package org.example.touch;

import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

// http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-2-building-the-touch-example/1763?tag=content;siu-container

public class Touch extends Activity implements OnTouchListener {
   private static final String TAG = "Touch" ;
   
	// Define matrices to move and zoom the image
	Matrix matrix = new Matrix();
	Matrix savedMatrix = new Matrix();
	PointF start = new PointF();
	PointF mid = new PointF();
	float oldDist = 0.0f;
   
   static final int NONE = 0;
   static final int DRAG = 1;
   static final int ZOOM = 2;
   int mode = NONE;
   
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      ImageView view = (ImageView) findViewById(R.id.imageView);
      view.setOnTouchListener(this);
   }
   
   @Override
   public boolean onTouch(View v, MotionEvent event) {
	   ImageView view = (ImageView)v;
	   // Dump touch event to log
	   dumpEvent(event);
	   
	   // Handle touch events
	   switch (event.getAction() & MotionEvent.ACTION_MASK) {
	   case MotionEvent.ACTION_DOWN:
		   savedMatrix.set(matrix);
		   start.set(event.getX(), event.getY());
		   Log.d(TAG, "mode=DRAG");
		   mode = DRAG;
		   break;
	   case MotionEvent.ACTION_UP:
	   case MotionEvent.ACTION_POINTER_UP:
		   mode = NONE;
		   Log.d(TAG, "mode=NONE");;
		   break;
	   case MotionEvent.ACTION_MOVE:
		   if (mode == DRAG) {
			   matrix.set(savedMatrix);
			   matrix.postTranslate(event.getX() - start.x, 
					   				event.getY() - start.y);
		   }
		   else if (mode == ZOOM) {
			   float newDist = spacing(event);
			   Log.d(TAG, "newDist="+newDist);
			   if (newDist > 10f) {
				   matrix.set(savedMatrix);
				   float scale = newDist / oldDist;
				   matrix.postScale(scale, scale, mid.x, mid.y);
				   matrix.postRotate(calcAngle(event),mid.x,mid.y);
			   }
		   }
		   break;
	   case MotionEvent.ACTION_POINTER_DOWN:
		   oldDist = spacing(event);
		   Log.d(TAG, "oldDist="+oldDist);
		   if (oldDist > 10.0f) {
			   savedMatrix.set(matrix);
			   midPoint(mid, event);
			   mode = ZOOM;
			   Log.d(TAG, "mode:ZOOM");
		   }
		   break;
	   }
	   
	   // Perform the trasformation
	   view.setImageMatrix(matrix);
	   
	   return true; // indicate event was handled
   }
   
   private float spacing(MotionEvent event) {
	   float x = event.getX(1) - event.getX(0);
	   float y = event.getY(1) - event.getY(0);
	   return FloatMath.sqrt(x * x + y * y);
   }
   
   private void midPoint(PointF point, MotionEvent event) {
	   float x = event.getX(0) + event.getX(1);
	   float y = event.getY(0) + event.getY(1);
	   point.set(x / 2, y / 2);
   }
   
   private float calcAngle(MotionEvent event) {
	   float x, y = 0.0f;
//	   if (event.getX(0) < event.getX(1)) {
		   x = event.getX(0) - event.getX(1);
		   y = event.getY(0) - event.getY(1);
//	   }
//	   else {
//		   x = event.getX(1) - event.getX(0);
//		   y = event.getY(1) - event.getY(0);
//	   }
	   float r = (float)Math.atan2(y, x);
	   r = (float)(Math.PI /2 + Math.toDegrees(r));
	   return r;
   }
   
   /** Show an event in the LogCat view, for debugging */
   private void dumpEvent(MotionEvent event) {
      String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
         "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
      StringBuilder sb = new StringBuilder();
      int action = event.getAction();
      int actionCode = action & MotionEvent.ACTION_MASK;
      sb.append("event ACTION_" ).append(names[actionCode]);
      if (actionCode == MotionEvent.ACTION_POINTER_DOWN
            || actionCode == MotionEvent.ACTION_POINTER_UP) {
         sb.append("(pid " ).append(
         action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
         sb.append(")" );
      }
      sb.append("[" );
      for (int i = 0; i < event.getPointerCount(); i++) {
         sb.append("#" ).append(i);
         sb.append("(pid " ).append(event.getPointerId(i));
         sb.append(")=" ).append((int) event.getX(i));
         sb.append("," ).append((int) event.getY(i));
         if (i + 1 < event.getPointerCount())
            sb.append(";" );
      }
      sb.append("]" );
      Log.d(TAG, sb.toString());
   }
}